/**
 * @file socket_client.cpp
 * @author fwy (2643660853@qq.com)
 * @brief 客户端套接字类实现
 * @version 0.2
 * @date 2025-08-17
 *
 * @copyright Copyright (c) 2025
 *
 */

#include "socket_client.h"
#include <cstring>

SocketClient::SocketClient()
{
    // 构造函数
}

SocketClient::~SocketClient()
{
    close();
}

bool SocketClient::connect(const std::string &server_ip, int server_port, const std::string &client_id)
{
    // 如果已经在连接中，先关闭旧连接
    if (socket_fd_ != -1)
    {
        close();
    }

    // 保存连接参数用于重连
    server_ip_ = server_ip;
    server_port_ = server_port;
    client_id_ = client_id;

    socket_fd_ = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd_ == -1)
    {
        std::cerr << "Client socket creation failed" << std::endl;
        return false;
    }

    sockaddr_in server_addr{};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);

    if (inet_pton(AF_INET, server_ip.c_str(), &server_addr.sin_addr) <= 0)
    {
        std::cerr << "Invalid address" << std::endl;
        close();
        return false;
    }

    std::cout << "Connecting to " << server_ip << ":" << server_port << std::endl;

    if (::connect(socket_fd_, (sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        std::cerr << "Connection failed" << std::endl;
        close();

        // 如果自动重连已启用，开始重连过程
        if (auto_reconnect_ && !reconnecting_)
        {
            reconnectThread();
        }
        return false;
    }

    running_ = true;
    connected_ = true;
    reconnect_attempts_ = 0;
    resetReconnectDelay();

    // 启动接收线程
    if (receive_thread_.joinable())
    {
        receive_thread_.join();
    }
    receive_thread_ = std::thread(&SocketClient::receiveThread, this);

    std::cout << "Connected to server at " << server_ip << ":" << server_port
              << " with client ID: " << client_id_ << std::endl;

    // 通知连接状态改变
    notifyConnectionChange(true);

    // 自动发送客户端标识
    sendIdentity();
    return true;
}

bool SocketClient::reconnect()
{
    if (isConnected())
    {
        return true; // 已经连接，无需重连
    }

    if (server_ip_.empty() || server_port_ == 0)
    {
        std::cerr << "Cannot reconnect: No previous connection information" << std::endl;
        return false;
    }

    return connect(server_ip_, server_port_, client_id_);
}

void SocketClient::setAutoReconnect(bool enable, int max_attempts, int initial_delay_ms, int max_delay_ms)
{
    auto_reconnect_ = enable;
    max_reconnect_attempts_ = max_attempts;
    initial_reconnect_delay_ = initial_delay_ms;
    max_reconnect_delay_ = max_delay_ms;
    resetReconnectDelay();
}

void SocketClient::resetReconnectDelay()
{
    current_reconnect_delay_ = initial_reconnect_delay_;
}

void SocketClient::increaseReconnectDelay()
{
    // 指数退避算法，每次增加1.5倍直到上限
    current_reconnect_delay_ = std::min(current_reconnect_delay_ * 3 / 2, max_reconnect_delay_);
}

void SocketClient::notifyConnectionChange(bool connected)
{
    if (connection_callback_)
    {
        connection_callback_(connected);
    }
}

void SocketClient::reconnectThread()
{
    // 确保之前的重连线程已经结束
    if (reconnect_thread_.joinable())
        reconnect_thread_.join();

    reconnect_thread_ = std::thread([this]()
                                    {
        reconnecting_ = true;
        std::cout << "Starting reconnection attempts..." << std::endl;

        while (auto_reconnect_ && !isConnected() &&
               (max_reconnect_attempts_ == -1 || reconnect_attempts_ < max_reconnect_attempts_))
        {
            reconnect_attempts_++;
            std::cout << "Reconnection attempt " << reconnect_attempts_
                      << " (delay: " << current_reconnect_delay_ << "ms)" << std::endl;

            // 彻底关闭旧 socket
            if (socket_fd_ != -1)
            {
                ::shutdown(socket_fd_, SHUT_RDWR);
                ::close(socket_fd_);
                socket_fd_ = -1;
            }

            // 创建新 socket 并尝试连接
            socket_fd_ = socket(AF_INET, SOCK_STREAM, 0);
            if (socket_fd_ != -1)
            {
                sockaddr_in server_addr{};
                server_addr.sin_family = AF_INET;
                server_addr.sin_port = htons(server_port_);
                if (inet_pton(AF_INET, server_ip_.c_str(), &server_addr.sin_addr) > 0)
                {
                    if (::connect(socket_fd_, (sockaddr *)&server_addr, sizeof(server_addr)) >= 0)
                    {
                        running_ = true;
                        connected_ = true;
                        resetReconnectDelay();

                        // 启动接收线程
                        if (receive_thread_.joinable())
                            receive_thread_.join();
                        receive_thread_ = std::thread(&SocketClient::receiveThread, this);

                        std::cout << "Reconnected to server at " << server_ip_ << ":" << server_port_
                                  << " with client ID: " << client_id_ << std::endl;

                        notifyConnectionChange(true);
                        sendIdentity();
                        reconnecting_ = false;
                        return;
                    }
                }
            }

            increaseReconnectDelay();
            std::this_thread::sleep_for(std::chrono::milliseconds(current_reconnect_delay_));
        }
        reconnecting_ = false; });

    reconnect_thread_.detach();
}

bool SocketClient::sendMessage(const std::string &message)
{
    if (!isConnected())
    {
        std::cerr << "Not connected to server" << std::endl;
        return false;
    }

    if (send(socket_fd_, message.c_str(), message.size(), 0) < 0)
    {
        std::cerr << "Failed to send message to server" << std::endl;
        // 发送失败可能是连接已断开
        connected_ = false;
        notifyConnectionChange(false);

        // 尝试重连
        if (auto_reconnect_ && !reconnecting_)
        {
            reconnectThread();
        }
        return false;
    }
    return true;
}

bool SocketClient::sendIdentity()
{
    if (!isConnected())
    {
        return false;
    }

    // 构造标识消息，JSON格式
    std::string identity_msg = "{\"type\":\"identity\",\"client_id\":\"" + client_id_ + "\"}";
    if (send(socket_fd_, identity_msg.c_str(), identity_msg.size(), 0) < 0)
    {
        std::cerr << "Failed to send identity message" << std::endl;
        // 发送失败可能是连接已断开
        connected_ = false;
        notifyConnectionChange(false);

        // 尝试重连
        if (auto_reconnect_ && !reconnecting_)
        {
            reconnectThread();
        }
        return false;
    }
    std::cout << "Sent identity message: " << identity_msg << std::endl;
    return true;
}

void SocketClient::setClientId(const std::string &client_id)
{
    client_id_ = client_id;
    if (isConnected())
    {
        sendIdentity();
    }
}

void SocketClient::close()
{
    running_ = false;
    connected_ = false;
    // auto_reconnect_ = false;
    reconnecting_ = false;

    if (socket_fd_ != -1)
    {
        ::shutdown(socket_fd_, SHUT_RDWR); // 唤醒阻塞的recv
        ::close(socket_fd_);
        socket_fd_ = -1;
    }

    if (receive_thread_.joinable())
    {
        receive_thread_.join();
    }

    if (reconnect_thread_.joinable())
    {
        reconnect_thread_.join();
    }
}

void SocketClient::receiveThread()
{
    char buffer[1024];
    while (running_ && socket_fd_ != -1)
    {
        // 使用select设置超时，避免服务端重启或断网时卡死
        fd_set readfds;
        FD_ZERO(&readfds);
        FD_SET(socket_fd_, &readfds);
        timeval tv;
        tv.tv_sec = 5; // 5秒超时
        tv.tv_usec = 0;

        int ret = select(socket_fd_ + 1, &readfds, nullptr, nullptr, &tv);
        if (ret > 0 && FD_ISSET(socket_fd_, &readfds))
        {
            ssize_t n = recv(socket_fd_, buffer, sizeof(buffer) - 1, 0);
            if (n <= 0)
            {
                if (running_)
                {
                    std::cerr << "Connection closed by server or network error" << std::endl;
                    connected_ = false;
                    notifyConnectionChange(false);

                    // 尝试重连
                    if (auto_reconnect_ && !reconnecting_)
                    {
                        reconnectThread();
                    }
                }
                break;
            }
            buffer[n] = '\0';

            if (message_callback_)
            {
                message_callback_(std::string(buffer));
            }
        }
        else if (ret == 0)
        {
            // 超时，可以在这里做心跳检测或其他处理
            // 例如：sendMessage("{\"type\":\"ping\"}");
            sendMessage("{\"type\":\"ping\"}");
            continue;
        }
        else
        {
            // select错误或socket异常
            if (running_)
            {
                std::cerr << "Socket select error or closed" << std::endl;
                connected_ = false;
                notifyConnectionChange(false);

                if (auto_reconnect_ && !reconnecting_)
                {
                    reconnectThread();
                }
            }
            break;
        }
    }
}